package org.six11.ss.server;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.six11.ss.server.bean.*;
import org.six11.util.Debug;
import org.six11.util.adt.MultiState;

/**
 * Stellasketch jsp pages hit the main servlet (Router) with a GET request, and it looks at the
 * action parameter (the key is the static string ACTION). It hopefully finds an associated instance
 * of the WebActionHandler in it's handy dandy map and invokes its 'handle' method.
 * 
 * @author Gabe Johnson <johnsogg@cmu.edu>
 */
public abstract class WebActionHandler {

  public static final String ACTION = "a";

  private static final BrowseWebActionHandler BrowseWebActionHandler = null;

  protected String name;
  protected String jsp;
  protected MultiState state;

  /**
   * 
   * @param actionName
   *          this web action handler's name (the value of the ACTION, e.g. a=showSketch would refer
   *          to a WebActionHandler named 'showSketch').
   * @param jsp
   *          the JSP file suitable to forward to after handling the action's main logic method. The
   *          value provided should work as the first argument ('servletPath') to forwardTo, e.g.
   *          "/showSketch.jsp" with the leading slash indicating the root of this web app's
   *          context.
   * @param ms
   *          the Stellasketch master state object, which also houses ongoing game data.
   */
  public WebActionHandler(String actionName, String jsp, MultiState ms) {
    this.name = actionName;
    this.jsp = jsp;
    this.state = ms;
  }

  /**
   * This method is responsible for taking care of whatever action the user demands.
   * 
   * Subclasses should implement 'handle' and load up the request object's attributes with whatever
   * data the JSP needs, and invoke 'forwardTo(..)'.
   * 
   * @param req
   *          the request object as received by the Router.
   * @param resp
   *          the response object as received by the Router.
   * @param context
   *          the servlet context object as received by the Router.
   */
  public abstract void handle(HttpServletRequest req, HttpServletResponse resp,
      ServletContext context) throws ServletException, IOException;

  public void handleWithHibernate(HttpServletRequest req, HttpServletResponse resp,
      ServletContext context) throws ServletException, IOException {
    getHibernate().setFlushMode(FlushMode.ALWAYS);
    Transaction tx = getHibernate().beginTransaction();
    try {
      handle(req, resp, context);
    } finally {
      tx.commit();
    }
  }

  protected void redo(String actionType, HttpServletRequest req, HttpServletResponse resp,
      ServletContext context) throws ServletException, IOException {
    req.setAttribute("a", actionType);
    forwardTo("/", req, resp, context);
  }

  protected void forwardTo(String servletPath, HttpServletRequest req, HttpServletResponse resp,
      ServletContext context) throws ServletException, IOException {
    context.getRequestDispatcher(servletPath).forward(req, resp);
  }

  protected void log(String what) {
    String n = getClass().getName();
    Debug.out(">>  " + n.substring(n.lastIndexOf('.') + 1), what);
  }

  protected void bug(String what) {
    String n = getClass().getName();
    Debug.out(n.substring(n.lastIndexOf('.') + 1), what);
  }

  protected Session getHibernate() {
    return AppletMessageHandler.sessionFactory.getCurrentSession();
  }

  protected void error(HttpServletRequest req, String msg) {
    req.setAttribute("errorMsg", msg);
  }
  
  protected boolean ok(String s) {
    return s != null && s.length() > 0;
  }

  protected Theme loadTheme(String id) {
    return (Theme) getHibernate().load(Theme.class, Integer.parseInt(id));
  }

  protected Clue loadClue(String id) {
    return (Clue) getHibernate().load(Clue.class, Integer.parseInt(id));
  }

  protected Sketch loadSketch(String id) {
    return (Sketch) getHibernate().load(Sketch.class, Integer.parseInt(id));
  }

  protected Person loadPerson(String id) {
    return (Person) getHibernate().load(Person.class, Integer.parseInt(id));
  }

  protected Round loadRound(String id) {
    return (Round) getHibernate().load(Round.class, Integer.parseInt(id));
  }

  protected Game loadGame(String id) {
    return (Game) getHibernate().load(Game.class, Integer.parseInt(id));
  }

  protected BrowseWebActionHandler getBrowseHandler() {
   Map<String, WebActionHandler> webHandlers = (Map<String, WebActionHandler>) state.getValue(ServerStateNames.WEB_ACTION_HANDLERS);
   return (BrowseWebActionHandler) webHandlers.get("browse");
  }
}
